{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random,datetime"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Position:\n",
    "    def __init__(self, x, y):\n",
    "        self.X = x\n",
    "        self.Y = y\n",
    "\n",
    "    def __str__(self):\n",
    "        return \"{},{}\".format(self.X, self.Y)\n",
    "\n",
    "    def __eq__(self, other):\n",
    "        return self.X == other.X and self.Y == other.Y\n",
    "\n",
    "    def __hash__(self):\n",
    "        return self.X * 1000 + self.Y\n",
    "\n",
    "class Board:\n",
    "    def __init__(self, positions, width, height):\n",
    "        board = [['.'] * width for _ in range(height)]\n",
    "\n",
    "        for index in range(len(positions)):\n",
    "            knightPosition = positions[index]\n",
    "            board[knightPosition.Y][knightPosition.X] = 'N'\n",
    "        self._board = board\n",
    "        self._width = width\n",
    "        self._height = height\n",
    "\n",
    "    def print(self):\n",
    "        # 0,0 prints in bottom left corner\n",
    "        for i in reversed(range(self._height)):\n",
    "            print(i, \"\\t\", ' '.join(self._board[i]))\n",
    "        print(\" \\t\", ' '.join(map(str, range(self._width))))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_attacks(location, boardWidth, boardHeight):\n",
    "    return [i for i in set(\n",
    "        Position(x + location.X, y + location.Y)\n",
    "        for x in [-2, -1, 1, 2] if 0 <= x + location.X < boardWidth\n",
    "        for y in [-2, -1, 1, 2] if 0 <= y + location.Y < boardHeight\n",
    "        and abs(y) != abs(x))]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "7 \t . . . . . . . .\n",
      "6 \t . . . . . . . .\n",
      "5 \t . . . . . . . .\n",
      "4 \t . . . . . . . .\n",
      "3 \t . . . . . . . .\n",
      "2 \t . N . . . . . .\n",
      "1 \t . . N . . . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n"
     ]
    }
   ],
   "source": [
    "n = get_attacks(Position(0,0),8,8)\n",
    "Board(n,8,8).print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "7 \t . . . . . . . .\n",
      "6 \t . . N . N . . .\n",
      "5 \t . N . . . N . .\n",
      "4 \t . . . . . . . .\n",
      "3 \t . N . . . N . .\n",
      "2 \t . . N . N . . .\n",
      "1 \t . . . . . . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n"
     ]
    }
   ],
   "source": [
    "n = get_attacks(Position(3,4),8,8)\n",
    "Board(n,8,8).print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_fitness(genes, boardWidth, boardHeight):\n",
    "    attacked = set(pos\n",
    "                   for kn in genes\n",
    "                   for pos in get_attacks(kn, boardWidth, boardHeight))\n",
    "    return len(attacked)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def display(candidate, startTime, boardWidth, boardHeight):\n",
    "    timeDiff = datetime.datetime.now() - startTime\n",
    "    board = Board(candidate.Genes, boardWidth, boardHeight)\n",
    "    board.print()\n",
    "\n",
    "    print(\"{}\\n\\t{}\\t{}\".format(\n",
    "        ' '.join(map(str, candidate.Genes)),\n",
    "        candidate.Fitness,\n",
    "        timeDiff))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def mutate(genes, boardWidth, boardHeight, allPositions, nonEdgePositions):\n",
    "    #随机交换8-10组基因，这个值也可以修改，一般来说，别太多，否则慢。\n",
    "    for i in range(random.randint(8,10)):\n",
    "        #构建一个由棋盘上所有的点所组成的字典\n",
    "        positionToKnightIndexes = dict((p, []) for p in allPositions)\n",
    "        #从种群的基因库中查看骑士的位置，然后把这些骑士能够攻击到的点，都加入到上面那个字典里面\n",
    "        # 结构是{点1:[骑士1的索引,骑士2的索引]……}\n",
    "        for i, knight in enumerate(genes):\n",
    "            for position in get_attacks(knight, boardWidth, boardHeight):\n",
    "                positionToKnightIndexes[position].append(i)\n",
    "        knightIndexes = set(i for i in range(len(genes)))\n",
    "        unattacked = []\n",
    "        #下面对每个点进行进行迭代，如果某个点没有任何一个骑士可以攻击到的话，把这个点记录下面\n",
    "        # 如果某个点，只有一个骑士可以攻击到，那个这个骑士的位置就太浪费\n",
    "        # 会把这个骑士先移除掉，设定为需要重新放位的\n",
    "        for kvp in positionToKnightIndexes.items():\n",
    "            if len(kvp[1]) > 1:\n",
    "                continue\n",
    "            if len(kvp[1]) == 0:\n",
    "                unattacked.append(kvp[0])\n",
    "                continue\n",
    "            for p in kvp[1]:  # len == 1\n",
    "                if p in knightIndexes:\n",
    "                    knightIndexes.remove(p)\n",
    "        \n",
    "        # 对于完全没有被攻击到的点，进行一次计算，计算出可以攻击到他们的位置\n",
    "        # 也就是潜在的要被攻击的点。\n",
    "        # 而且这些潜在的点，需要是非边界上的点。\n",
    "        # 如果未被攻击到的点小于等于0了，那么需要计算的潜在点，就是非边界点。\n",
    "        potentialKnightPositions = \\\n",
    "            [p for positions in\n",
    "             map(lambda x: get_attacks(x, boardWidth, boardHeight),\n",
    "                 unattacked)\n",
    "             for p in positions if p in nonEdgePositions] \\\n",
    "                if len(unattacked) > 0 else nonEdgePositions\n",
    "        \n",
    "        #选择需要替换的基因库里面的基因\n",
    "        geneIndex = random.randrange(0, len(genes)) \\\n",
    "            if len(knightIndexes) == 0 \\\n",
    "            else random.choice([i for i in knightIndexes])\n",
    "        # 在前致电里面，选择一个位置，设置为新的骑士的位置\n",
    "        position = random.choice(potentialKnightPositions)\n",
    "        genes[geneIndex] = position\n",
    "        return Chromosome(genes, get_fitness(genes,boardWidth, boardHeight))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fnGetRandomPosition():\n",
    "    return random.choice(nonEdgePositions)\n",
    "\n",
    "def create(fnGetRandomPosition, expectedKnights):\n",
    "    genes = [fnGetRandomPosition() for _ in range(expectedKnights)]\n",
    "    return genes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Chromosome:\n",
    "    def __init__(self, genes, fitness):\n",
    "        self.Genes = genes\n",
    "        self.Fitness = fitness"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "boardHeight = 8\n",
    "boardWidth = 8\n",
    "expectedKnights = 14"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "boardHeight = 10\n",
    "boardWidth = 10\n",
    "expectedKnights = 22"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "allPositions = [Position(x, y)\n",
    "                        for y in range(boardHeight)\n",
    "                        for x in range(boardWidth)]\n",
    "nonEdgePositions = [i for i in allPositions\n",
    "                            if 0 < i.X < boardWidth - 1 and\n",
    "                            0 < i.Y < boardHeight - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_best():\n",
    "    startTime = datetime.datetime.now()\n",
    "    optimalFitness = boardWidth * boardHeight\n",
    "    geneset = create(fnGetRandomPosition,expectedKnights)\n",
    "    best = Chromosome(geneset, get_fitness(geneset,boardHeight,boardWidth))\n",
    "    if best.Fitness == optimalFitness:\n",
    "        return best\n",
    "    num = 0\n",
    "    while True:\n",
    "        child = mutate(best.Genes, boardWidth, boardHeight, \n",
    "                       allPositions, nonEdgePositions)\n",
    "        num +=1\n",
    "        if best.Fitness > child.Fitness:\n",
    "            continue\n",
    "        #display(child,startTime, boardWidth, boardHeight)\n",
    "        if not child.Fitness > best.Fitness:\n",
    "            best = child\n",
    "        if child.Fitness == optimalFitness:\n",
    "            break\n",
    "        best = child\n",
    "    return (best,num)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "7 \t . . . . . . . .\n",
      "6 \t . . . . . . . .\n",
      "5 \t . . N N N . . .\n",
      "4 \t . . . N . N . .\n",
      "3 \t . . N . N . . .\n",
      "2 \t . N N . N . . .\n",
      "1 \t . . . N . . N .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "2,3 4,2 3,4 2,2 4,5 3,5 4,5 2,5 6,1 4,3 5,4 1,2 3,1 4,5\n",
      "\t49\t0:00:00.001996\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . . . . . .\n",
      "5 \t . . N N N N . .\n",
      "4 \t . . . . . N . .\n",
      "3 \t . . N . N . . .\n",
      "2 \t . N N . N . . .\n",
      "1 \t . . . N . . N .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "2,3 4,2 5,5 2,2 4,5 3,5 4,5 2,5 6,1 4,3 5,4 1,2 3,1 4,5\n",
      "\t53\t0:00:00.004985\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . . . . . .\n",
      "5 \t . . N N N N . .\n",
      "4 \t . . N . . N . .\n",
      "3 \t . . N . N . . .\n",
      "2 \t . N N . N . . .\n",
      "1 \t . . . N . . N .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "2,3 4,2 5,5 2,2 4,5 3,5 4,5 2,5 6,1 4,3 5,4 1,2 3,1 2,4\n",
      "\t56\t0:00:00.007979\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . . N . . .\n",
      "5 \t . . N N N N . .\n",
      "4 \t . . N . . N . .\n",
      "3 \t . . N . N . . .\n",
      "2 \t . N N . N . . .\n",
      "1 \t . . . N . . N .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "2,3 4,2 5,5 2,2 4,6 3,5 4,5 2,5 6,1 4,3 5,4 1,2 3,1 2,4\n",
      "\t58\t0:00:00.010971\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . . N . . .\n",
      "5 \t . . N N N N . .\n",
      "4 \t . . N . . . . .\n",
      "3 \t . . . . N . N .\n",
      "2 \t . . N . N . . .\n",
      "1 \t . . N N N . N .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "4,1 4,2 5,5 2,2 4,6 3,5 4,5 2,5 6,1 4,3 2,1 6,3 3,1 2,4\n",
      "\t58\t0:00:00.017968\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . . . . . .\n",
      "5 \t . N N N N N N .\n",
      "4 \t . . N N . . . .\n",
      "3 \t . . . . N N N .\n",
      "2 \t . . N N . . . .\n",
      "1 \t . . . N . . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "3,4 3,2 6,5 2,2 5,3 3,5 4,5 5,5 1,5 4,3 2,5 6,3 3,1 2,4\n",
      "\t58\t0:00:00.031916\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . . . . . .\n",
      "5 \t . N N N N . N .\n",
      "4 \t . . . N N . . .\n",
      "3 \t . N . . N N N .\n",
      "2 \t . . N N . . . .\n",
      "1 \t . . . N . . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "3,4 3,2 6,5 2,2 5,3 3,5 4,5 1,3 1,5 4,3 2,5 6,3 3,1 4,4\n",
      "\t58\t0:00:00.034917\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . . . . . .\n",
      "5 \t . N N . N N N .\n",
      "4 \t . . . N N . . .\n",
      "3 \t . N . . N N N .\n",
      "2 \t . . N N . . N .\n",
      "1 \t . . . . . . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "3,4 3,2 6,5 2,2 5,3 6,2 4,5 1,3 1,5 4,3 2,5 6,3 5,5 4,4\n",
      "\t59\t0:00:00.036902\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . N N . N . .\n",
      "5 \t . . . N N N . .\n",
      "4 \t . N . N . . . .\n",
      "3 \t . . . . . N . .\n",
      "2 \t . N N N . . . .\n",
      "1 \t . . . N N . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "3,4 3,2 1,4 2,2 5,3 2,6 4,5 5,6 3,5 4,1 3,1 3,6 1,2 5,5\n",
      "\t59\t0:00:00.054885\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . N . . N . .\n",
      "5 \t . . . N N N . .\n",
      "4 \t . N . N . . . .\n",
      "3 \t . N . . . N . .\n",
      "2 \t . N N N . . . .\n",
      "1 \t . . . N N . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "3,4 3,2 1,4 2,2 5,3 2,6 4,5 5,6 3,5 4,1 3,1 1,3 1,2 5,5\n",
      "\t60\t0:00:00.055851\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . N . . . .\n",
      "5 \t . N . N N . N .\n",
      "4 \t . . N . N . N .\n",
      "3 \t . . N . . . N .\n",
      "2 \t . . N . N . . .\n",
      "1 \t . . N . N . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "6,5 4,5 2,1 6,4 1,5 3,6 2,4 2,2 4,2 4,1 3,5 2,3 4,4 6,3\n",
      "\t60\t0:00:00.102725\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . N N . N .\n",
      "5 \t . N . . N . N .\n",
      "4 \t . . N . . . N .\n",
      "3 \t . . N . . . N .\n",
      "2 \t . . N . N . . .\n",
      "1 \t . . N . N . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "6,5 4,5 2,1 6,4 1,5 3,6 2,4 2,2 4,2 4,1 4,6 2,3 6,6 6,3\n",
      "\t62\t0:00:00.113695\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . . . . . .\n",
      "5 \t . N N . N N N .\n",
      "4 \t . . N . . . N .\n",
      "3 \t . . N N . N N .\n",
      "2 \t . . N . . . . .\n",
      "1 \t . . N . N . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "6,5 6,4 2,1 5,3 1,5 3,3 5,5 2,2 4,1 2,5 2,4 2,3 6,3 4,5\n",
      "\t62\t0:00:00.129652\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . . . . . .\n",
      "5 \t . N . . N N N .\n",
      "4 \t . . N . . . N .\n",
      "3 \t . . N N . N N .\n",
      "2 \t . . N . . . N .\n",
      "1 \t . . N . N . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "6,5 6,4 2,1 5,3 1,5 3,3 5,5 2,2 4,1 6,2 2,4 2,3 6,3 4,5\n",
      "\t62\t0:00:00.133642\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . . . . . .\n",
      "5 \t . N N . N N N .\n",
      "4 \t . . N . . . N .\n",
      "3 \t . . N N . . N .\n",
      "2 \t . . N . . . N .\n",
      "1 \t . . N . N . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "6,5 6,4 5,5 2,1 1,5 3,3 2,5 2,2 4,1 6,2 2,4 2,3 6,3 4,5\n",
      "\t62\t0:00:00.139626\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . . N . . .\n",
      "5 \t . N N . N N N .\n",
      "4 \t . . N . . . N .\n",
      "3 \t . . N . . . N .\n",
      "2 \t . . N . . . N .\n",
      "1 \t . . N . N . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "6,5 6,4 5,5 2,1 1,5 2,4 2,5 2,2 4,1 6,2 4,6 2,3 6,3 4,5\n",
      "\t62\t0:00:00.143615\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . . N . . .\n",
      "5 \t . N N . N N N .\n",
      "4 \t . . N . . . N .\n",
      "3 \t . . N . . . N .\n",
      "2 \t . . N . . . N .\n",
      "1 \t . . N . N . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "6,5 6,4 5,5 2,1 1,5 2,4 2,5 2,2 4,1 6,2 4,6 2,3 6,3 4,5\n",
      "\t62\t0:00:00.145644\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . N . . . .\n",
      "5 \t . N . N . N . .\n",
      "4 \t . N . . N N . .\n",
      "3 \t . N . . . N . .\n",
      "2 \t . N . N . N . .\n",
      "1 \t . . . N . N . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "5,3 5,2 5,1 1,5 4,4 3,2 5,4 3,5 5,5 3,6 1,4 1,2 3,1 1,3\n",
      "\t62\t0:00:00.347112\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . N . . . .\n",
      "5 \t . N . N N N . .\n",
      "4 \t . N . . . N . .\n",
      "3 \t . N . . . N . .\n",
      "2 \t . N . N . N . .\n",
      "1 \t . . . N . N . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "5,3 5,2 5,1 1,5 4,5 3,2 5,4 3,5 5,5 3,6 1,4 1,2 3,1 1,3\n",
      "\t63\t0:00:00.350107\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . N . . . .\n",
      "5 \t . N N N . N . .\n",
      "4 \t . N . . . N . .\n",
      "3 \t . N . . . N . .\n",
      "2 \t . N . N . N . .\n",
      "1 \t . . . N . N . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "1,4 2,5 5,1 1,5 3,5 3,2 5,4 5,3 5,5 3,6 1,3 1,2 3,1 5,2\n",
      "\t63\t0:00:00.368016\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . . . . N . .\n",
      "5 \t . N N . . N . .\n",
      "4 \t . . N N N N . .\n",
      "3 \t . . . . . . . .\n",
      "2 \t . . N N N N . .\n",
      "1 \t . . N . . N . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "1,5 4,4 3,2 5,1 2,1 2,5 2,2 5,6 5,5 3,4 5,2 2,4 4,2 5,4\n",
      "\t63\t0:00:00.683872\n",
      "7 \t . . . . . . . .\n",
      "6 \t . . N . . N . .\n",
      "5 \t . . N N N N . .\n",
      "4 \t . . . . . . . .\n",
      "3 \t . . N N N N . .\n",
      "2 \t . N N . . N N .\n",
      "1 \t . . . . . . . .\n",
      "0 \t . . . . . . . .\n",
      " \t 0 1 2 3 4 5 6 7\n",
      "2,2 5,6 5,3 6,2 1,2 3,3 3,5 4,3 2,6 2,5 4,5 2,3 5,5 5,2\n",
      "\t64\t0:00:00.862366\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "970"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "get_best()[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "n = []\n",
    "for i in range(100):\n",
    "    n.append(get_best()[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([26., 30., 18., 11.,  3.,  4.,  3.,  4.,  0.,  1.]),\n",
       " array([  15.,  246.,  477.,  708.,  939., 1170., 1401., 1632., 1863.,\n",
       "        2094., 2325.]),\n",
       " <a list of 10 Patch objects>)"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.hist(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "543.12"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "numpy.mean(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
